package main

import (
	"database/sql"
	"encoding/json"
	"reflect"

	"test.com/fusion"
	"test.com/worlddb"
)

type charSpawnDialogTableRow struct {
	SpawnID uint32  `json:"spawnId"`
	Entry   uint32  `json:"entry"`
	MapID   uint32  `json:"map_id"`
	MapType uint32  `json:"map_type"`
	X       float32 `json:"x"`
	Y       float32 `json:"y"`
	Z       float32 `json:"z"`
}

func getAllCharSpawn4DialogTable(db *sql.DB) ([]*charSpawnDialogTableRow, error) {
	var charSpawnRows []*charSpawnDialogTableRow
	rows, err := db.Query("SELECT `spawnId`,`entry`,`map_id`,`map_type`," +
		"`x`,`y`,`z` FROM `creature_spawn`")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		var charSpawnRow charSpawnDialogTableRow
		err = rows.Scan(&charSpawnRow.SpawnID, &charSpawnRow.Entry,
			&charSpawnRow.MapID, &charSpawnRow.MapType,
			&charSpawnRow.X, &charSpawnRow.Y, &charSpawnRow.Z)
		if err == nil {
			charSpawnRows = append(charSpawnRows, &charSpawnRow)
		} else {
			return nil, err
		}
	}
	return charSpawnRows, nil
}

type charProtoDialogTableRow struct {
	CharTypeId uint32 `json:"charTypeId"`
	Level      uint32 `json:"level"`
}

func getAllCharProto4DialogTable(db *sql.DB) ([]*charProtoDialogTableRow, error) {
	var charProtoRows []*charProtoDialogTableRow
	rows, err := db.Query("SELECT `charTypeId`,`level` FROM `char_prototype`")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		var charProtoRow charProtoDialogTableRow
		err = rows.Scan(&charProtoRow.CharTypeId, &charProtoRow.Level)
		if err == nil {
			charProtoRows = append(charProtoRows, &charProtoRow)
		} else {
			return nil, err
		}
	}
	return charProtoRows, nil
}

func getAllCharNames(db *sql.DB) (map[uint32]string, error) {
	return getAllKeyI18Ns(db,
		"char_prototype", "charTypeId", worlddb.STRING_TEXT_TYPE_CHAR_NAME)
}

func getCharInfo(db *sql.DB, charTypeId uint32) (*worlddb.CharPrototype, error) {
	var charInfo *worlddb.CharPrototype
	charInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(charInfo), "`charTypeId`=?", charTypeId)
	if err != nil {
		return nil, err
	}
	if charInfoVals.Len() < 1 {
		return nil, sql.ErrNoRows
	}
	return charInfoVals.Index(0).Interface().(*worlddb.CharPrototype), nil
}

func getCharInstanceJsonData(db *sql.DB, charTypeId uint32) ([]byte, error) {
	var err error
	var charProto charWebPrototype
	charProto.CharName, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_CHAR_NAME, charTypeId)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	charProto.CharDesc, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_CHAR_DESC, charTypeId)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	charProto.CharInfo, err = getCharInfo(db, charTypeId)
	if err != nil {
		return nil, err
	}
	charData, err := json.Marshal(
		fusion.MarshalEntityToInterface(&charProto, "json"))
	if err != nil {
		return nil, err
	}
	return charData, nil
}

func newCharInstance(tx *sql.Tx, charName, charDesc string) (uint32, error) {
	charInfo := worlddb.CharPrototype{}
	charTypeId, err := fusion.SaveJsontableToDB(tx, &charInfo)
	if err != nil {
		return 0, err
	}
	err = setI18Ns(tx,
		worlddb.STRING_TEXT_TYPE_CHAR_NAME, charTypeId, charName,
		worlddb.STRING_TEXT_TYPE_CHAR_DESC, charTypeId, charDesc)
	if err != nil {
		return 0, err
	}
	return charTypeId, nil
}

func copyCharInstance(db *sql.DB, tx *sql.Tx, charTypeId uint32) (uint32, error) {
	var charInfo *worlddb.CharPrototype
	charInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(charInfo), "`charTypeId`=?", charTypeId)
	if err != nil {
		return 0, err
	}
	if charInfoVals.Len() < 1 {
		return 0, sql.ErrNoRows
	}
	charInfo = charInfoVals.Index(0).Interface().(*worlddb.CharPrototype)
	charInfo.CharTypeId = 0
	ID, err := fusion.SaveJsontableToDB(tx, charInfo)
	if err != nil {
		return 0, err
	}
	err = copyI18Ns(db, tx,
		worlddb.STRING_TEXT_TYPE_CHAR_NAME, charTypeId, ID,
		worlddb.STRING_TEXT_TYPE_CHAR_DESC, charTypeId, ID)
	if err != nil {
		return 0, err
	}
	return ID, nil
}

func deleteCharInstance(tx *sql.Tx, charTypeId uint32) error {
	_, err := tx.Exec(
		"DELETE FROM `char_prototype` WHERE `charTypeId`=?", charTypeId)
	if err != nil {
		return err
	}
	return nil
}

func saveCharInstance(tx *sql.Tx, charProto *CharPrototype) error {
	err := setI18Ns(tx,
		worlddb.STRING_TEXT_TYPE_CHAR_NAME,
		charProto.CharInfo.CharTypeId, charProto.CharName,
		worlddb.STRING_TEXT_TYPE_CHAR_DESC,
		charProto.CharInfo.CharTypeId, charProto.CharDesc)
	if err != nil {
		return err
	}
	_, err = fusion.SaveJsontableToDB(tx, charProto.CharInfo)
	if err != nil {
		return err
	}
	return nil
}
